<template>
    <n-form
        ref="formRef"
        :model="formState"
        label-placement="left"
        label-align="right"
        label-width="5rem"
        show-feedback
        v-bind="formProps"
    >
        <n-form-item
            v-for="item in items"
            :label="item.label"
            :path="<string>item.field"
            :rule="item.rule"
            :key="item.field"
            :feedback="item.feedback"
        >
            <slot
                v-if="$slots[<string>item.field]"
                :name="item.field"
                :modelValue="formState[<string>item.field]"
                :updateModelValue="
                    (newValue: string | number) =>
                        (formState[<string>item.field] = newValue)
                "
                :props="item.props"
            />
            <!-- 单行文本 & 多行文本 -->
            <n-input
                v-if="item.component === 'Input'"
                clearable
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />

            <!-- 数字 -->
            <n-input-number
                v-if="item.component === 'InputNumber'"
                clearable
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />

            <!-- 下拉 -->
            <n-select
                v-if="item.component === 'Select'"
                clearable
                filterable
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />
            <n-tree-select
                v-if="item.component === 'TreeSelect'"
                clearable
                filterable
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />

            <!-- 单选 -->
            <RadioGroup
                v-if="item.component === 'RadioGroup'"
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />

            <!-- 复选 -->
            <n-checkbox
                v-if="item.component === 'Checkbox'"
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />
            <CheckboxGroup
                v-if="item.component === 'CheckboxGroup'"
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />

            <!-- 日期选择 -->
            <n-date-picker
                v-if="item.component === 'DatePicker'"
                clearable
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />

            <!-- 上传图片 -->
            <UploadImage
                v-if="item.component === 'UploadImage'"
                clearable
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />

            <!-- VmEditor -->
            <VmEditor
                v-if="item.component === 'VmEditor'"
                clearable
                v-model:value="formState[<string>item.field]"
                v-bind="item.props"
            />
        </n-form-item>

        <slot name="tool" v-if="$slots.tool"></slot>
        <n-form-item label=" " v-else>
            <n-space>
                <n-button @click="onReset" secondary :disabled="loading"
                    >清空</n-button
                >
                <n-button
                    @click="onSubmit"
                    type="primary"
                    secondary
                    :loading="loading"
                    >提交</n-button
                >
            </n-space>
        </n-form-item>
    </n-form>
</template>

<script setup lang="ts">
import { computed, onUnmounted, PropType, ref, watch } from 'vue'
import { FormItemsConfig, FormStateType } from '../types'
import { FormInst, FormProps } from 'naive-ui'
import RadioGroup from '../components/RadioGroup.vue'
import CheckboxGroup from '../components/CheckboxGroup.vue'
import { UploadImage } from '@/components/upload'
import { VmEditor } from '@/components/editor'

const emits = defineEmits<{
    submit: []
    reset: []
    'update:value': [newValue: FormStateType]
}>()

const props = defineProps({
    items: {
        type: Object as PropType<FormItemsConfig<any>>,
        required: true
    },
    value: {
        type: Object,
        default: () => ({})
    },
    loading: {
        type: Boolean,
        default: () => false
    },
    formProps: {
        type: Object as PropType<FormProps>,
        default: () => ({})
    }
})

const formRef = ref<FormInst>()
const formState = computed({
    get: () => props.value,
    set: (val) => emits('update:value', val)
})

// 处理select不能刷新的问题
function undefined2null() {
    const fields = props.items.map((item) => item.field)

    fields.forEach((field) => {
        if (!Object.prototype.hasOwnProperty.call(props.value, field)) {
            formState.value[<string>field] = null
        } else {
            if (formState.value[<string>field] === undefined) {
                formState.value[<string>field] = null
            }
        }
    })
}

const stop = watch(
    () => props.value,
    () => {
        undefined2null()
        formRef.value?.restoreValidation()
    },
    { deep: true }
)
onUnmounted(() => stop())

function onSubmit() {
    formRef.value
        ?.validate()
        .then(() => {
            emits('submit')
        })
        .catch((_) => {
            // 占位
        })
}

function onReset() {
    formRef.value?.restoreValidation()
    emits('reset')
}

defineExpose({
    validate: () => formRef.value?.validate(),
    restoreValidation: () => formRef.value?.restoreValidation()
})
</script>
